#!/usr/bin/env python
#  Copyright (C) 2008 Monadsphere <monadli@gmail.com>
#
# This file is part of Monadsphere.
#
# Monadsphere is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Monadsphere is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Monadsphere. If not, see <http://www.gnu.org/licenses/>.

'''
  Base classes to support abstracted functionalities.
'''

from monadsphere.util import *

class Var:
  '''
    This class wraps a native variable on client side.
  '''

  def __init__(self, doc, val = None):
    '''
      Constructor that needs a document to generate a name.
    '''
    self.name = doc.nextName()
    self.createHandle(val)

  def createHandle(self, val = None):
    '''
      Creates a native signature.
    '''
    if (val is None):
      print 'var ' + self.name
    else:
      print 'var ' + self.name + '=' + str(val)

  def __add__(self, other):
    '''
      Returns string concatnation.
    '''
    return self.name + str(other)

  def __radd__(self, other):
    '''
      Returns string concatination.
    '''
    return str(other) + self.name

  def __getitem__(self, key):
    return Var(self.doc, self.name + '[' + str(key) + ']')

  def __eq__(self, other):
    return Var(self.doc, self.name + '==' + str(other))

  def __ge__(self, other):
    return Var(self.doc, self.name + '>=' + str(other))

  def __gt__(self, other):
    return Var(self.doc, self.name + '>' + str(other))

  def __le__(self, other):
    return Var(self.doc, self.name + '<=' + str(other))

  def __lt__(self, other):
    return Var(self.doc, self.name + '<' + str(other))

  def __ne__(self, other):
    return Var(self.doc, self.name + '!=' + str(other))

  def __str__(self):
    return self.name

class Number(Var):
  def inc(self, val):
    print self + '+=' + str(val)

  def dec(self, val):
    print self + '-=' + str(val)

class Component(Var):
  def __init__(self, doc, val = None):
    self.doc = doc
    Var.__init__(self, doc, val)

class Element(Component):
  '''
    This class serves as a base for component.

    This class should never be explicitly instantiated by calling its
    constructor. Instead, it should always be created by calling
    doc.createElement(..) that calls Element.createHandle(...).
  '''

  def __init__(self, doc, val = None):
    self.doc = doc
    Var.__init__(self, doc, val)

  def setOptions(self, options):
    '''
      Sets any element specific options.
    '''
    pass

  def getAttribute(self, name):
    '''
      Returns an attribute.
    '''
    pass

  def hasAttribute(self, name):
    '''
      Returns an attribute.
    '''
    pass

  def removeAttribute(self, name):
    '''
      Returns an attribute.
    '''
    pass

  def setAttribute(self, name, value):
    '''
      Sets an attribute.
    '''
    pass

  def hasChildNodes(self):
    '''
      Returns an attribute.
    '''
    pass

  def setId(self, id):
    '''
      Sets id.
    '''
    pass

  def appendChild(self, element):
    '''
      Appends a child.
    '''
    pass

  def getParentNode(self):
    '''
      Returns parent node.
    '''
    pass

  def setStyle(self, name, value):
    '''
      Sets a style.
    '''
    pass

  def addEventListener(self, type, path, useCapture):
    '''
      Adds an event listener.
    '''
    pass


class EventListener(Var):
  '''
    Abstract base for event listener.
  '''
  def __init__(self, doc):
    Var.__init__(self, doc)
    self.doc = doc

  def createHandle(self, val):
    pass

class Document:
  '''
    A document is an element holder that manages relationship between an
    element and its native handle. This class can be extended to represent
    any types of document, such as HTML, Flex, etc.
  '''

  class NameManager:
    def __init__(self):
      '''
        Manages names on client side.
      '''
      self.num = 0

    def nextName(self):
      '''
        Returns next name, which starts from '_1_'.
      '''
      self.num = self.num + 1
      return '_' + str(self.num) + '_'

  def __init__(self, doc = None):
    '''
      Document constructor.
    '''
    if (doc is None):
      self.doc = Document.NameManager()
    else:
      self.doc = doc

  def nextName(self):
    '''
      Returns next available variable name.
    '''
    return self.doc.nextName()

  def createElement(self, type, **options):
    '''
      Creates an element of Element type with options and stores the handle
      on client side.
    '''
    if issubclass(type, Element):
      elm = type(self)
      elm.setOptions(options)
      if ('id' in options):
        self.setElementId(elm, options['id'])
      return elm
    raise TypeError, 'createElement needs Element type'

  def getElementById(self, type, id):
    '''
      Returns an element of Element type by id through getting native handle
      from client side.
    '''
    if issubclass(type, Element):
      elm = type(self, 'monadsphere.ids[' + StrWrap(id) + ']')

      elm.id = id
      return elm
    raise TypeError, 'getElementById needs Element type'

  def createElementHandle(self, name, tagName):
    '''
      Creates a native handle. This is usually called by an element
      in createHandle(...).
    '''
    pass

  def setElementId(self, elm, id):
    '''
      Sets id to an element, which basically registers the element to
      object monadsphere.
    '''
    print 'monadsphere.ids[' + StrWrap(id) + ']=' + elm

class Data(Var):
  def __init__(self, doc):
    Var.__init__(self, doc, '{}')

  def add(self, name, value):
    print self + '.' + name + '=' + StrWrap(value)

  def send(self, actionName):
    print 'monadsphere.remoteCall(' + StrWrap(actionName) + ', ' + self + ')'
